﻿using System.IdentityModel.Tokens.Jwt;
using CodeIsBug.Common.Components.Cache;
using CodeIsBug.Common.Helper;
using CodeIsBug.Common.Model;
using Microsoft.AspNetCore.Http;

namespace CodeIsBug.Common.Token;

public class TokenService(ICacheService cacheService, IHttpContextAccessor httpContextAccessor)
    : ITokenService
{
    /// <summary>
    /// 请求头的前缀
    /// </summary>
    private readonly string _tokenTag = "Authorization";

    /// <summary>
    /// 生成token
    /// </summary>
    /// <param name="tokenData"></param>
    /// <returns></returns>
    public async Task<(string accessToken, string refreshToken )> GenerateTokenAsync(TokenData tokenData)
    {
        //var token = Guid.NewGuid().ToString("N");
        //tokenData.LoginTime = DateTime.Now;
        //tokenData.ExpireTime = DateTime.Now.AddMinutes(expiresTime);
        ////有效期为半个小时
        var (accessToken, refreshToken) = new JwtHelper().GenerateJwtToken(tokenData);
        var accessTokenTimeSecond = 30 * 60;
        var refreshTokenTimeSecond = 30 * 24 * 60 * 60;
        tokenData.LoginTime = DateTime.Now;
        tokenData.ExpireTime = DateTime.Now.AddSeconds(accessTokenTimeSecond);
        //有效期为半个小时
        if (tokenData.UserId != Guid.Empty)
            await cacheService.SetAsync(Constant.Cache.UserAccessToken + accessToken, tokenData, accessTokenTimeSecond);
        if (tokenData.UserId != Guid.Empty)
            await cacheService.SetAsync(Constant.Cache.UserRefreshToken + refreshToken, refreshToken,
                refreshTokenTimeSecond);
        return (accessToken, refreshToken);
    }

    /// <summary>
    /// 检查Token
    /// </summary>
    /// <param name="token">token</param>
    /// <returns></returns>
    public async Task<bool> ValidateToken(string token)
    {
        if (token == null) throw new ArgumentNullException(nameof(token));

        if (string.IsNullOrWhiteSpace(token)) return false;
        //是否在缓存，是否过期
        var userinfo = await cacheService.GetAsync<TokenData>(Constant.Cache.UserAccessToken + token);
        if (ReferenceEquals(userinfo, null) || userinfo.ExpireTime < DateTime.Now) return false;
        return true;
    }

    /// <summary>
    /// 刷新token
    /// </summary>
    /// <param name="accessToken">token</param>
    /// <returns></returns>
    public async Task<(string accessToken, string refreshToken )> RefreshTokenAsync(string accessToken)
    {
        var jwtSecurityTokenHandler = new JwtSecurityTokenHandler(); //这个类是老朋友了
        bool isCan = jwtSecurityTokenHandler.CanReadToken(accessToken); //验证Token格式
        var tokenInfo = await cacheService.GetAsync<TokenData>(Constant.Cache.UserRefreshToken + accessToken.Replace("Bearer ",""));
        // tokeninfo.ExpireTime = DateTime.Now.AddMinutes(_expiresTime);
        // //expiresTime 内操作，变增加30分钟的有效期
        // cacheService.Set(Constant.Cache.UserAccessToken + token, tokeninfo, 60 * _expiresTime);
        return await GenerateTokenAsync(tokenInfo);
    }

    /// <summary>
    /// 解析token
    /// </summary>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<TokenData> ParseTokenAsync(string token)
    {
        var tokenInfo = await cacheService.GetAsync<TokenData>(Constant.Cache.UserAccessToken + token);
        return tokenInfo;
    }

    /// <summary>
    /// 获取heard的token
    /// </summary>
    /// <returns></returns>
    /// <exception cref="SystemException"></exception>
    public Task<string> GetHeadersToken()
    {
        if (httpContextAccessor.HttpContext == null) throw new SystemException("参数错误");
        if (httpContextAccessor.HttpContext.Request.Headers.ContainsKey(_tokenTag))
            return Task.FromResult(httpContextAccessor.HttpContext.Request.Headers[_tokenTag].ToString());
        return Task.FromResult(string.Empty);
    }

    /// <summary>
    /// 获取当前登录的用户信息
    /// </summary>
    /// <returns></returns>
    public async Task<TokenData> GetCurrentUserInfo()
    {
        var token = await GetHeadersToken();
        try
        {
            return await ParseTokenAsync(token);
        }
        catch (Exception)
        {
            return new TokenData();
        }
    }
}